/*** Created Time: 2022年5月16日 16:55:51 ***/
/*** Author: Eric                        ***/

#ifndef _MY_TASK_H_
#define _MY_TASK_H_

#include <onix/types.h>
#include <onix/list.h>

#define     KERNEL_USER     (0)   // 内核用户ID
#define     NORMAL_USER     (1)   // 普通用户ID

#define     TASK_NAME_LEN   (16)  // 任务名字长度

// 定义返回值为void类型的入口函数，指示入口地址
// 其中该入口函数的输入形参为空
typedef void target_t(void);

// 任务状态
typedef enum task_state_t {
    TASK_INIT,     // 初始化
    TASK_RUNNING,  // 执行
    TASK_READY,    // 就绪
    TASK_BLOCKED,  // 阻塞
    TASK_SLEEPING, // 睡眠
    TASK_WAITING,  // 等待 
    TASK_DIED,     // 死亡
} task_state_t;

typedef struct task_t
{
    u32 *stack;               // 内核栈，指示栈顶
    list_node_t node;         // 任务阻塞节点，当一个任务被阻塞时将任务压入链表中
    task_state_t state;       // 任务状态
    u32 priority;             // 任务优先级
    u32 ticks;                // 剩余时间片
    u32 jiffies;              // 上次执行时全局时间片
    char name[TASK_NAME_LEN]; // 任务名
    u32 uid;                  // 用户id
    pid_t pid;                // 任务id
    pid_t ppid;               // 父任务id
    u32 pde;                  // 页目录物理地址
    struct bitmap_t *vmap;    // 进程虚拟内存位图
    u32 brk;                  // 进程堆内存最高地址
    int status;               // 进程特殊状态
    pid_t waitpid;            // 进程等待的 pid
    u32 magic;                // 内核魔数，用于检测栈溢出
} task_t;


// ABI调用约定被调用方callee需要保存的寄存器
// 进程切换之前需要保存，切换之后需要恢复
// 任务栈帧
typedef struct task_frame_t
{
    u32 edi;
    u32 esi;
    u32 ebx;
    u32 ebp;
    void (*eip)(void);
} task_frame_t;

// 中断帧
typedef struct intr_frame_t
{
    u32 vector;

    u32 edi;
    u32 esi;
    u32 ebp;
    // 虽然 pushad 把 esp 也压入，但 esp 是不断变化的，所以会被 popad 忽略
    u32 esp_dummy;

    u32 ebx;
    u32 edx;
    u32 ecx;
    u32 eax;

    u32 gs;
    u32 fs;
    u32 es;
    u32 ds;

    u32 vector0;

    u32 error;

    u32 eip;
    u32 cs;
    u32 eflags;
    u32 esp;
    u32 ss;
} intr_frame_t;

// 当前运行的任务/进程
task_t *running_task(void);
// 任务调度函数
void schedule(void);

// exit 系统调用
void task_exit(int status);
// fork 系统调用
pid_t task_fork(void);
// waitpid 系统调用
pid_t task_waitpid(pid_t pid, int32 *status);
// yield系统调用
void task_yield(void);
// 任务阻塞
void task_block(task_t *task, list_t *blist, task_state_t state);
// 解除任务阻塞
void task_unblock(task_t *task);

// 任务睡眠
void task_sleep(u32 ms);
// 任务唤醒
void task_wakeup(void);
// 将任务切换到用户态
void task_to_user_mode(target_t target);

// 获取进程 id
pid_t sys_getpid(void);
// 获取父进程 id
pid_t sys_getppid(void);

#endif